<?php
/**************************************************************************
 * Naanal PHP Framework, Simple, Efficient and Developer Friendly
 * Ver 3.0, Copyright (C) <2010>  <Tamil Amuthan. R>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ************************************************************************/

class ClsWrapper
{
    protected $id=null;
    public $fldID="id";
    private $partitionID=false;
    private $fldPartitionID=false;
    protected $module="";
    protected $otherVar=array();
    protected $objPDO=null;
    private $tableName=null;
    private $isTableExist=false;
    protected $arrField=array();
    protected $arrFilter=array();
    protected $arrJoin=array();
    protected $arrConfigVar=array();
    protected $db="";
    //protected $module="";
    public static $instanceCount=0;
    protected $multipleRecordWhere=array();
    protected $arrForeignKey=array();
    
    protected $arrError=array();
    protected static $arrErrorStatic=array();
    /**
        * 
        * number of record to query
        * @var int
        */
    protected $itemPerPage=10;

    protected function __construct($module)
    {
        if(!isset($module)) return null;
        $this->module=$module;
        $this->arrConfigVar=ClsNaanalApplication::getConfigVars($module);
        $this->db=$this->arrConfigVar["database"]===true?ClsNaanalApplication::getDefaultDatabase():$this->arrConfigVar["database"];
        
        $this->tableName=$this->arrConfigVar["table"];
        $this->objPDO=ClsNaanalPDO::getNamedInstance($this->module,$this->db); 
        
        if(!isTableExist($this->db, $this->tableName))
        {
            die("Module Table {$this->db}.{$this->tableName} not exist");
        }
        $this->isTableExist=true;
        $this->arrField=getTableFields($this->db, $this->tableName);
        $this->arrForeignKey=getForiegnKeys($this->db, $this->tableName);
        /*if(isLogged())
        {
            $client_id=ClsNaanalSession::getInstance()->getPanelData("client_id");
            ///if client_id exist in the table, no join performed. else join will perform based on user id
            if(in_array("client_id", $this->arrField))
            {
                $this->arrFilter[]=array("field"=>"client_id","data"=>$client_id);
            }
            else
            {
                $this->arrJoin[]=array("table"=>"client","onSource"=>"user_id","onDestination"=>"user_id","type"=>"left");
                $this->arrFilter[]=array("field"=>"client.id","data"=>$client_id);
            }
        }*/
        if($this->arrField)
        foreach($this->arrField as $fld)
        {
            if(isset($this->$fld) || isset($this->otherVar[$fld])){}
            else
            {
                $this->$fld="";
            }
        }
        $objNaanalSession=  ClsNaanalSession::getInstance();
        $this->fldPartitionID=isset(ClsConfig::$FLD_PARTITION)?ClsConfig::$FLD_PARTITION:false;
        $partitionHook=getHook("partition_id");
        if($partitionHook)
        {
            $this->partitionID=$partitionHook();
        }
        else
        {
            if($objNaanalSession->getLoginPanel()!="guest")
            {
                if($objNaanalSession->isPanelDataSet("partition_id"))
                {
                    $this->partitionID=$objNaanalSession->isPanelDataSet("partition_id");
                }
                else
                {
                    $this->partitionID=$objNaanalSession->isPanelDataSet("client_id")?$objNaanalSession->getPanelData("client_id"):0;
                }
            }
        }
        addLog("db:".$this->db." table:".$this->tableName);
    }
    
    public function get_module_name()
    {
        return $this->module;
    }

    private function loadConfigVar()
    {
        $modulePath=ClsNaanalApplication::getModulePath($this->module);
        if($modulePath)
        {
            include $modulePath."{$this->module}/config.php";
            if(file_exists(NAANAL_APP_PATH."module_config/{$this->module}.php"))
            {
                include NAANAL_APP_PATH."module_config/{$this->module}.php";
            }
            $this->arrConfigVar=get_defined_vars();
            unset($this->arrConfigVar["modulePath"]);
        }
    }
    public function getConfigData($var)
    {
        if(isset($this->arrConfigVar[$var]))
        {
            return $this->arrConfigVar[$var];
        }
        else
        {
            return null;
        }
    }
    public static function &getInstance($module=false)
    {
        if(is_null($module)) return null;
        if($module===false)
        {
            $wrapper=get_class($this);
            $module=  ClsNaanalApplication::getModuleNameByWrapper($wrapper);
        }
        $arrConfigVar=ClsNaanalApplication::getConfigVars($module);
        if(!isset($arrConfigVar["database"]) || $arrConfigVar["database"]===false)
        {
            self::$arrErrorStatic[]="database variable not set in config file";
            $wModule = false;
            return $wModule;
        }
        if(!isset($arrConfigVar["table"]) || empty($arrConfigVar["table"]))
        {
            self::$arrErrorStatic[]="table variable not set in config file";
            $wModule = false;
            return $wModule;
        }
        self::$instanceCount=self::$instanceCount + 1;
        $wrapper=  getModuleWrapperName($module);
        ClsNaanalApplication::loadWrapper($module);
        if(!class_exists($wrapper)) 
        {
            $wrapper="ClsWrapper";
        }
        $wModule=new $wrapper($module);
        
        return $wModule;
    }
    
    public static function getStaticError()
    {
        if(empty(self::$arrErrorStatic)) return false;
        return self::$arrErrorStatic;
    }
    
    function getFields()
    {
        return $this->arrField;
    }
    
    public function getRow($index=0)
    {
        $row=array();
        foreach($this->arrField as $field)
        {
            $row[$field]=$this->get($field);
        }
        return $row;
    }

    public function getError()
    {
        return $this->arrError;
    }
    
    function &searchObject($arrWhere=array(),$pageNum=0)
    {
        addLog("search in table {$this->tableName} for page {$pageNum}");
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[]=$where;
        }
        $objSql=getNaanalLibObject("ClsNaanalSQL");
        $objSql->addTable($this->tableName);
        if($this->arrJoin)
            $objSql->addJoinAsArray($this->arrJoin);
        if($pageNum)
                $objSql->setLimit(($pageNum-1)*$this->itemPerPage, $this->itemPerPage);
        $objSql->addWhereAsArray($arrWhere);
        $sql=$objSql->render();
        $this->objPDO->setQuery($sql);
        $arrObj=$this->objPDO->getAllObject(get_class($this));
        $arrError=$this->objPDO->getError();
        if($arrError)
        {
            foreach($arrError as $error)
            {
                $this->arrError[]=$error;
            }
            $arrObj=false;
            return $arrObj;
        }
        return $arrObj;
    }

    function getDistinctColumn($fieldName,$arrWhere=array(),$withID=true)
    {
        if(is_array($fieldName)) trace("Invalid input for $fieldName");
        if($withID) addLog("get column from {$this->tableName} with ID");
        else addLog("get column from {$this->tableName}");
        $arrObj=$this->getObjectList($arrWhere,true);
        $arrCol=array();
        foreach($arrObj as $obj)
        {
            $getfieldName="get_".$fieldName;
            if($withID) $arrCol[$obj->get_id()]=$obj->$getfieldName();
            else $arrCol[$obj->$getfieldName()]=$obj->$getfieldName();
        }
        return $arrCol;
    }

    function getColumn($fieldName,$arrWhere=array(),$withID=true)
    {
        if(is_array($fieldName)) trace("Invalid input for $fieldName");
        if($withID) addLog("get column from {$this->tableName} with ID");
        else addLog("get column from {$this->tableName}");
        $arrAssoc=$this->getList($fieldName,$arrWhere);
        $arrCol=array();
        if($arrAssoc)
        foreach($arrAssoc as $row)
        {
            $getfieldName="get_".$fieldName;
            if($withID) $arrCol[$row["id"]]=$row[$fieldName];
            else $arrCol[$row[$fieldName]]=$row[$fieldName];
        }
        return $arrCol;
    }
    
    function &getDBTable($arrWhere=array())
    {
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[]=$where;
        }
        $objDBTable=new ClsNaanalDBTable($this->tableName,$arrWhere,$this->objPDO);
        return $objDBTable;
    }
    
    /**
        * 
        * if fieldName is string, return the field only in the row. 
        * if it is an array return list of row with all the fields in the row
        * @param $fieldName
        * @param $arrWhere
        */
    function getList($fieldName,$arrWhere=array())
    {
        if(!is_array($fieldName))
        {
            $fieldName=array($fieldName);
        }
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[]=$where;
        }
        $objSql=getNaanalLibObject("ClsNaanalSQL");
        $objSql->addField("id");
        if($fieldName)
        foreach($fieldName as $field)
        {
            $objSql->addField($field);
        }
        $objSql->addTable($this->tableName);
        if($this->arrJoin)
            $objSql->addJoinAsArray($this->arrJoin);
        if($arrWhere) $objSql->addWhereAsArray($arrWhere);
        $sql=$objSql->render();
        $this->objPDO->setQuery($sql);
        return $this->objPDO->getAllAssoc();
    }
    function getAssocList($arrWhere=array(),$isDistinct=true)
    {
        addLog("inside getObjList");
        $objSql=getNaanalLibObject("ClsNaanalSQL");
        $objSql->isDistinct=$isDistinct;
        $objSql->addTable($this->tableName);
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[]=$where;
        }
        if($this->arrJoin)
            $objSql->addJoinAsArray($this->arrJoin);
        if($arrWhere) $objSql->addWhereAsArray($arrWhere);
        $sql=$objSql->render(); 
        addLog($sql);
        $this->objPDO->setQuery($sql);
        return $this->objPDO->getAllAssoc();
    }
    function getObjectList($arrWhere=array(),$isDistinct=true)
    {
        addLog("inside getObjList");
        $objSql=getNaanalLibObject("ClsNaanalSQL");
        $objSql->isDistinct=$isDistinct;
        $objSql->addTable($this->tableName);
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[]=$where;
        }
        if($this->arrJoin)
            $objSql->addJoinAsArray($this->arrJoin);
        if($arrWhere) $objSql->addWhereAsArray($arrWhere);
        $sql=$objSql->render();
        addLog($sql);
        $this->objPDO->setQuery($sql);
        return $this->objPDO->getAllObject(get_class($this),array($this->module));
    }

    function getObjectListBySQL($sql)
    {
        $this->objPDO->setQuery($sql);
        return $this->objPDO->getAllObject(get_class($this),array($this->module));
    }
    
    function &getAllAttribute()
    {
        $arrAttribute=$this->otherVar;
        return $arrAttribute;
    }

    public function __set($name, $value)
    {
        $this->set($name,$value);
    }

    public function __get($name)
    {
        return $this->get($name);
    }

    public function get($name)
    {
        if(isset($this->$name))
        {
            return $this->$name;
        }
        else if(array_key_exists($name, $this->otherVar))
        {
            return $this->otherVar[$name];
        }
        else
        {
            $arrKey=getForiegnKeys($this->db, $this->tableName);
            $fkey=$name."_id";
            $ftable="";
            if(array_key_exists($fkey, $arrKey))
            {
                    $ftable=$arrKey[$fkey]["table"];
            }
            /**
                * checking for getting foreign table object
                */
            if(empty($ftable)) 
            {
                trace("Undefined Property: {$this->db}.{$this->tableName}.{$name}");
                die("Undefined Property: {$this->db}.{$this->tableName}.{$name}"); 
            }
            //$cls="ClsW".ucfirst($name);
            //$obj=new $cls();
            $obj=ClsWrapper::getInstance($name);
            /**
                * if $fkey set, this object is already loaded and the value for foreign key also set
                * else it is empty object. so return empty foreign object
                */
            if(isset($this->$fkey) || isset($this->otherVar[$fkey]))
            {
                $obj->loadObject($this->$fkey);
            }
            return $obj;
        }
    }

    public function set($name,$value)
    {
        if(isset($this->$name))
        {
            $this->$name=$value;
        }
        else
        {
            $this->otherVar[$name]=$value;
        }
    }
    
    private function getType($field)
    {
        return isset($this->arrConfigVar["fields"][$field])?$this->arrConfigVar["fields"][$field]["type"]:false;
    }

    public function __call($name, $arguments)
    {
        if(($pos=strpos($name, "get_"))!==false)
        {
            $variable=substr($name, $pos+4);
            if(($pos=strpos($variable, "_lookup"))!==false || $variable=="lookup")
            {
                if(!isset($arguments[0])) trace("The first parameter(field name - string type) is mandatory for function call '{$name}'");
                /**
                    * if $pos is 0, then there is no reference table and self table will be used 
                    */
                if($variable=="lookup")
                {
                    $ftable=$this->tableName;
                }
                else
                {
                    $ftable=substr($variable, 0, $pos);
                }
                $cls="ClsW".ucfirst($ftable);
                if(!class_exists($cls))
                {
                    ClsNaanalApplication::loadClass($cls);
                }
                $obj=new $cls();
                if(!isset($arguments[1]))
                {
                    $arguments[1]=array();
                }
                if(!isset($arguments[2]))
                {
                    $arguments[2]=true;
                }
                return $obj->getColumn($arguments[0],$arguments[1],$arguments[2]);
            }
            else if(($pos=strpos($variable, "_object"))!==false)
            {
                /**
                    * if $pos is 0, then there is no reference table and self table will be used 
                    */
                $ftable=substr($variable, 0, $pos);
                $fldForeignKey=$ftable."_id";
                if(isset($this->arrForeignKey[$fldForeignKey]))
                {
                    $dataForeignKey=$this->$fldForeignKey;
                }
                else
                {
                    trace("Foreign key not exist in table {$this->tableName} for the table {$ftable}");
                }
                $cls="ClsW".ucfirst($ftable);
                if(!class_exists($cls))
                {
                    ClsNaanalApplication::loadClass($cls);
                }
                $obj=new $cls();
                $obj->loadObject($dataForeignKey);
                return $obj;
            }
            else
            {
                $variableType=$this->getType($variable);
                
                if($variableType=="date")
                {
                    $data=(int)$this->get($variable);
                    $arrDate=array();
                    $arrDate["value"]=$data;
                    $arrDate["day"]=date("j",$data);
                    $arrDate["month"]=date("n",$data);
                    $arrDate["year"]=date("Y",$data);
                    $arrDate["hour"]=intval(date("G",$data));
                    $arrDate["minute"]=intval(date("i",$data));
                    $arrDate["second"]=intval(date("s",$data));
                    if($arrDate["hour"]>12 && ($arrDate["minute"]>0 || $arrDate["second"]>0))
                    {
                        $arrDate["meridiem"]="PM";
                    }
                    else
                    {
                        $arrDate["meridiem"]="AM";
                    }
                    return $arrDate;
                }
                else if($variableType=="duration")
                {
                    $data=$this->get($variable);
                    $arrData=explode(" ",$data);
                    $arrDuration["duration"]=$arrData[0];
                    $arrDuration["type"]=isset($arrData[1])?$arrData[1]:"";
                    return $arrDuration;
                }
                else
                {
                    return $this->get($variable);
                }
            }
        }
        else if(($pos=strpos($name, "set_"))!==false)
        {
            $variable=substr($name, $pos+4);
            $variableType=$this->getType($variable);
            if($variableType=="date")
            {
                $arrDate=$arguments[0];
                $meridiem=isset($arrDate["meridiem"]) && $arrDate["meridiem"]=="PM" ? 12 : 0;
                $hour=isset($arrDate["hour"])?intval($arrDate["hour"]):0;
                $hour = $hour + $meridiem;
                $minute=isset($arrDate["minute"])?intval($arrDate["minute"]):0;
                $second=isset($arrDate["second"])?intval($arrDate["second"]):0;
                $month=isset($arrDate["month"])?intval($arrDate["month"]):0;
                $day=isset($arrDate["day"])?intval($arrDate["day"]):0;
                $year=isset($arrDate["year"])?intval($arrDate["year"]):0;
                $dataToSet=mktime($hour, $minute, $second, $month, $day, $year);
            }
            else if($variableType=="duration")
            {
                $arrDuration=$arguments[0];
                $dataToSet="{$arrDuration["duration"]} {$arrDuration["type"]}";
            }
            else
            {
                $dataToSet=$arguments[0];
            }
            $this->set($variable,$dataToSet);
        }
    }
    public function get_id()
    {
        return $this->id;
    }
    public function set_id($id)
    {
        $this->id=$id;
    }
    protected function add($sql,$arrParam=null)
    {
        if(is_null($arrParam)) $this->objPDO->setQuery($sql);		
        else $this->objPDO->setQuery($sql,$arrParam);
        return $this->objPDO->lastInsertId();
    }
    protected function modify($sql,$arrParam=null)
    {
        if(empty($this->id)) trace("This object has empty ID");
        if(is_null($arrParam)) $this->objPDO->setQuery($sql);		
        else $this->objPDO->setQuery($sql,$arrParam);
    }
    public function remove()
    {
        if(empty($this->id)) trace("This object has empty ID");
        $sql="DELETE FROM `{$this->tableName}` WHERE `id`=".$this->id;
        $this->objPDO->setQuery($sql);
        $this->id=null;
    }
    protected function &getWhereSqlFromWhereArray($arrWhere)
    {
        if($this->arrFilter)
        foreach($this->arrFilter as $where)
        {
            $arrWhere[$where["field"]]=$where["data"];
        }
        $arr=array();
        foreach($arrWhere as $k=>$v)
        {
            $arr[]="`{$k}`='{$v}'";
        }
        $sql=implode(" and ",$arr);
        return $sql;
    }
    /**
        * 
        * @param array $arrWhere - associative array with key as field and value as data for where
        */
    public function isRecordExist($arrWhere)
    {
        $sqlWhere=$this->getWhereSqlFromWhereArray($arrWhere);
        $sql="select * from {$this->tableName} where ".$sqlWhere;
        $this->objPDO->setQuery($sql);
        $arrRow=$this->objPDO->getAllRow();
        if($arrRow)
        {
            return true;
        }			
        else
            return false;
    }
    /**
        * 
        * @param array $arrWhere - associative array with key as field and value as data for where
        */
    public function getRecordID($arrWhere)
    {
        $sqlWhere=$this->getWhereSqlFromWhereArray($arrWhere);
        $sql="select * from {$this->tableName} where ".$sqlWhere;
        $this->objPDO->setQuery($sql);
        $arrAssoc=$this->objPDO->getAllAssoc();
        if($arrAssoc)
        {
            return $arrAssoc[0]["id"];
        }			
        else
            return 0;
    }
    /**
        *  
        * if the id is set, the datas are updated to the table.
        * if the id is not set, the datas are inserted into the table
        * if $arrFldUnique is set, the values of fields in that array is checked. if current value
        * matches existing values, the datas are updated.(if data already exist it will be updated) 
        */
    public function update($arrFldUnique=array())
    {
        $sql="";
        $arrFldVal=array();
        $isInsert=false;
        if(empty($this->arrField)) 
        {
            trace("Unexpected Error. Contact your site adminsitrator");
            die("Unexpected Error. Contact your site adminsitrator"); 
        }
        if($this->arrField)
        {
            foreach($this->arrField as $fld)
            {
                if($fld=="id") continue;
                $arrFldVal[$fld]=$this->$fld;
                /*if(isset($this->$fld)) 
                else if(isset($this->otherVar[$fld])) 
                {
                    $arrFldVal[$fld]=$this->otherVar[$fld];
                }*/
            }
        }
        if(empty($this->id))
        {
            $arrFld=array();
            $arrVal=array();
            foreach($arrFldVal as $fld=>$val)
            {
                $arrFld[]=$fld;
                if(method_exists($this, "beforeFieldInsert"))
                {
                    $hookData=$this->beforeFieldInsert($fld,$val);
                    if(!is_null($hookData))
                    {
                        $arrVal[]=$hookData;
                    }
                    else
                    {
                        $arrVal[]=$val;
                    }
                }
                else if($hook=getHook("beforeFieldInsert"))
                {
                    $hookData=$hook($fld,$arrFldVal);
                    if(!is_null($hookData))
                    {
                        $arrVal[]=$hookData;
                    }
                    else
                    {
                        $arrVal[]=$val;
                    }
                }
                else
                {
                    $arrVal[]=$val;
                }
            }
            if($arrFldUnique)
            {
                $where="";
                foreach($arrFldUnique as $fld=>$data)
                {
                    if(empty($where))
                    {
                        $where="`{$fld}`='".$data."'";
                    }	
                    else
                    {
                        $where=$where." and `{$fld}`='".$data."'";
                    }
                }
                if(!empty($where))
                {
                    $sql="select * from {$this->tableName} where ".$where;
                    $this->objPDO->setQuery($sql);
                    $arr=$this->objPDO->getAllAssoc();
                    /**
                        * if duplicate data not in database insert else update
                        */
                    if(empty($arr))
                    {
                        $sql="INSERT INTO ".$this->tableName." (`".implode("`,`",$arrFld)."`) values ('".implode("','",$arrVal)."')";
                        $isInsert=true;
                    }
                    else 
                    {
                        $arrFld=array();
                        foreach($arrFldVal as $fld=>$val)
                        {
                            $arrFld[]="`".$fld."`='".$val."'";
                        }
                        $sql="UPDATE ".$this->tableName." SET ".implode(",",$arrFld)." WHERE id=".$arr[0]["id"];
                        //$this->id=$arr[0]["id"];
                    }
                }
            }
            else
            {
                $sql="INSERT INTO ".$this->tableName." (`".implode("`,`",$arrFld)."`) values ('".implode("','",$arrVal)."')";
                $isInsert=true;
            }
        }
        else
        {
            $arrFld=array();
            foreach($arrFldVal as $fld=>$val)
            {
                if(method_exists($this, "beforeFieldUpdate"))
                {
                    $val=$this->beforeFieldUpdate($fld,$val);
                }
                else if($hook=getHook("beforeFieldUpdate"))
                {
                    $hookval=$hook($fld,$arrFldVal);
                    $val=is_null($hookval)?$val:$hookval;
                }
                $arrFld[]="`".$fld."`='".$val."'";
            }
            $sql="UPDATE ".$this->tableName." SET ".implode(",",$arrFld)." WHERE id=".$this->id;
            if(empty($arrFld)) trace("Unexpected Error. Contact your site adminsitrator");
        }

        $this->objPDO->setQuery($sql);
        if($isInsert)
        {
            return $this->objPDO->lastInsertId();
        }
        else
        {
            return $this->id;
        }
    }
    public function load($id=0)
    {
        return $this->loadObject($id);
    }
    public function loadObject($id=0)
    {
        if(empty($id)) $id=$this->id;
        if(empty($id))
        {
            addLog("id not set in object: Table: {$this->tableName}");
            return false;
        }
        if(empty($this->objPDO))
        {
            return false;
        }
        $sql="SELECT * FROM `$this->tableName` WHERE `{$this->fldID}`='$id'";
        if($this->fldPartitionID && $this->partitionID)
        {
            if(in_array($this->fldPartitionID, $this->arrField))
            {
                $sql=$sql." and {$this->fldPartitionID}='{$this->partitionID}'";
            }
        }
        $this->objPDO->setQuery($sql);
        $arrAssoc=$this->objPDO->getAllAssoc();
        if($arrAssoc[0])
        {
            foreach($arrAssoc[0] as $k=>$v)
            {
                if(method_exists($this, "beforeFieldLoadObject"))
                {
                    $v=$this->beforeFieldLoadObject($k,$v);
                }
                $this->$k=$v;
            }
            return true;
        }
        else
        {
            $db=$this->objPDO->getDatabase();
            addLog("Data Not found while a Data Expected. DB: {$db}, Table: {$this->tableName} and Sql: {$sql}");
            return false;
        }
    }
    protected function setFromArray(&$arr)
    {
        if(isset($arr["id"])) $this->id=$arr["id"];
    }
    function getArray()
    {
        $arr=$this->otherVar;
        $arr["id"]=$this->id;  		
        return $arr;
    }

    function setArray($arr)
    {
        if(isset($arr["id"])) 
        {
            $this->id=$arr["id"];
            unset($arr["id"]);
        }
        foreach($this->arrField as $fld)
        {
            if(isset($arr[$fld])) 
            {
                $fieldType=$this->getType($fld);
                /**
                    * if field type is date, 
                    * the date in $_REQUEST must be array(associative array) of date(date or day,month and year),(time or hour, minute and second). 
                    * if time not exist, it is assumed that the date component has all the date,month,year,hour,minute and second
                    */
                $data="";
                if($fieldType=="date")
                {
                    if(!is_array($arr[$fld]))
                    {
                        die("The date must be named as array in html forms");
                    }
                    $date=0;
                    $month=0;
                    $year=0;
                    $hour=0;
                    $minute=0;
                    $second=0;
                    if(isset($arr[$fld]["time"]))
                    {
                        $tmpArrTime=  explode(":", $arr[$fld]["time"]);
                        $hour=(int)$tmpArrTime[0];
                        $minute=isset($tmpArrTime[1])?(int)$tmpArrTime[1]:0;
                        $second=isset($tmpArrTime[2])?(int)$tmpArrTime[2]:0;
                    }
                    else if(isset($arr[$fld]["hour"]))
                    {
                        $hour=(int)$arr[$fld]["hour"];
                        $minute=isset($arr[$fld]["minute"])?(int)$arr[$fld]["minute"]:0;
                        $second=isset($arr[$fld]["second"])?(int)$arr[$fld]["second"]:0;
                    }

                    if(isset($arr[$fld]["date"]))
                    {
                        $tmptime=strtotime($arr[$fld]["date"]);
                        $day=date("j",$tmptime);
                        $month=date("n",$tmptime);
                        $year=date("Y",$tmptime);

                        $hour=isset($hour)?$hour:date("G",$tmptime);
                        $minute=isset($minute)?$minute:intval(date("i",$tmptime));
                        $second=isset($second)?$second:intval(date("s",$tmptime));
                    }
                    else
                    {
                        /**
                            * if day component not specified, it assumes the first day of month 
                            */
                        $day=isset($arr[$fld]["day"])?(int)$arr[$fld]["day"]:1;
                        /**
                            * if month component not specified, it assumes the first month of year
                            */
                        $month=isset($arr[$fld]["month"])?(int)$arr[$fld]["month"]:0;
                        $year=(int)$arr[$fld]["year"];
                        $hour=isset($hour)?$hour:date("G",$tmptime);
                        $minute=isset($minute)?$minute:intval(date("i",$tmptime));
                        $second=isset($second)?$second:intval(date("s",$tmptime));
                    }
                    /**
                    * if meridem is PM, the hour is added with 12 to convert 24 hours format 
                    */
                    if(isset($arr[$fld]["meridem"]) && $arr[$fld]["meridem"]="PM")
                    {
                        $hour=$hour+12;
                    }
                    $data=mktime($hour, $minute, $second, $month, $day, $year);
                }
                else if($fieldType=="duration")
                {
                    if(!is_array($arr[$fld]))
                    {
                        die("The duration must be named as array in html forms");
                    }
                    $hour=0;
                    $minute=0;
                    $second=0;
                    if(isset($arr[$fld]["time"]))
                    {
                        $tmpArrTime=  explode(":", $arr[$fld]["time"]);
                        $hour=(int)$tmpArrTime[0];
                        $minute=isset($tmpArrTime[1])?(int)$tmpArrTime[1]:0;
                        $second=isset($tmpArrTime[2])?(int)$tmpArrTime[2]:0;
                    }
                    else if(isset($arr[$fld]["hour"]))
                    {
                        $hour=(int)$arr[$fld]["hour"];
                        $minute=isset($arr[$fld]["minute"])?(int)$arr[$fld]["minute"]:0;
                        $second=isset($arr[$fld]["second"])?(int)$arr[$fld]["second"]:0;
                    }
                    $data=$hour*3600+$minute*60+$second;
                }
                else
                {
                    $data=$arr[$fld];
                }
                if(isset($this->$fld)) $this->$fld=$data;
                else $this->otherVar[$fld]=$data;
            }
        }
        return $arr;
    }
    function refreshTable($module)
    {
        if(empty($this->db)) trace("Unexpected Error. Please contact your site admistrator");
        if(!isTableExist($this->db, $module))
        {
            createTable($module);
        }
    }
    function removeTable()
    {

    }
    function truncateTable()
    {

    }
    public function getUI() 
    {
        $table=$this->tableName;
        $ClsUI="ClsU".ucfirst($table);
        $objUI=new $ClsUI($this);
        return $objUI;
    }
    function isTableExist()
    {
        /*$sql="SELECT COUNT(*) as tot FROM information_schema.tables WHERE table_schema = '{$this->db}' AND table_name = '{$this->tableName}';";
        trace($sql);
        $this->objPDO->setQuery($sql);
        $arrRow = $this->objPDO->getAllRow();
        if(is_array($arrRow) && count($arrRow)>0) return true;
        return false;*/
        return $this->isTableExist;
    }
    function createTable()
    {
        $sql="CREATE TABLE {$this->db}.{$this->tableName} (id INT NOT NULL AUTO_INCREMENT, primary key(id))ENGINE=InnoDB;";
        $this->objPDO->setQuery($sql);
    }
    function isFieldExist($fieldname)
    {
        $sql="SELECT count(*) AS tot FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='{$this->db}' AND TABLE_NAME = '{$this->tableName}' AND COLUMN_NAME = '{$fieldname}'";
        $this->objPDO->setQuery($sql);
        $arrRow = $this->objPDO->getAllRow();
        if(is_array($arrRow) && count($arrRow)>0) return true;
        return false;
    }
    function addField($fieldname,$fieldtype,$size=null,$defaultvalue=null,$after=null) 
    {
        $fieldtype=trim($fieldtype);
        $fieldtype=strtoupper($fieldtype);
        if($fieldtype=="string")
        {
            $fieldtype="VARCHAR";
            if(is_null($size))
            {
                $size=255;
            }
        }
        else if($fieldtype=="number")
        {
            $fieldtype="INT";
            if(is_null($size))
            {
                $size=14;
            }
        }
        else if($fieldtype=="boolean")
        {
            $fieldtype="INT";
            if(is_null($size))
            {
                $size=1;
            }
        }
        else if($fieldtype=="date")
        {
            $fieldtype="INT";
            if(is_null($size))
            {
                $size=14;
            }
        }
        else if($fieldtype=="reference")
        {
            $fieldtype="INT";
            if(is_null($size))
            {
                $size=14;
            }
        }
        $sql="ALTER TABLE {$this->db}.{$this->tableName} ADD {$fieldname} {$fieldtype}({$size})";
        if(!is_null($after))
        {
            $sql=$sql." ".$after;
        }
        $this->objPDO->setQuery($sql);
    }
}
?>